// std_random.hxx


#ifndef _BLOGS_STD_RANDOM
#define _BLOGS_STD_RANDOM


#include <random>

#include "array.hxx"


namespace blogs
{


using std::knuth_b;
using std::uniform_real_distribution;


class Std_Random
{

  private:

    static
    knuth_b
    __Engine__;


    static
    uniform_real_distribution<double>
    __Distri__;


  public:

    /*
     * Set random seed.
     *
     */
    static
    void
    set_seed(long);


    /*
     * Generate a real ranging [0, 1).
     *
     */
    static
    double
    random();


    /*
     * Generate an integer ranging [0, N).
     *
     */
    static
    int
    uniform(int);


    /*
     * Generate an integer ranging [lo, hi).
     *
     */
    static
    int
    uniform(int, int);


    /*
     * Generate a long integer ranging [0, N).
     *
     */
    static
    long
    uniform(long);


    /*
     * Generate a long integer ranging [lo, hi-1).
     *
     */
    static
    long
    uniform(long, long);


    /*
     * Generate a double ranging [lo, hi).
     *
     */
    static
    double
    uniform(double, double);


    /*
     * Generate a random boolean from a Bernoulli distribution.
     *
     */
    static
    bool
    bernoulli(double = 0.5);


    /*
     * Generate a random real number from a Gaussian distribution,
     * with mean and standard deviation.
     *
     */
    static
    double
    gaussian(double = 0.0, double = 1.0);


    /*
     * Generate a random integer from a Poisson distribution,
     * with the mean of lambda.
     *
     */
    static
    int
    poisson(double = 0.5);


    /*
     * Generate a random integer from a Geometric distribution,
     * with the success probability.
     *
     */
    static
    int
    geometric(double = 0.5);


    /*
     * Generate a random integer from a Discrete distribution,
     * with the probabilities.
     *
     */
    static
    int
    discrete(Array<double> const&);


    /*
     * Shuffle the array.
     *
     */
    template <class _T>
    static
    void
    shuffle(Array<_T> & a)
    {
        int n = a.size(), r;
        for (int i = 0; i < n; ++i) {
            r = i + uniform(long(n-i));     // between i and n-1
            _T t = a[i];
            a[i] = a[r];
            a[r] = t;
        }
    }


    /*
     * Shuffle the array.
     *
     */
    template <class _T>
    static
    void
    shuffle(Array<_T> & a, int b, int e)
    {
        int r;
        for (int i = b; i < e; ++i) {
            r = i + uniform(long(e-i));     // between i and e-1
            _T t = a[i];
            a[i] = a[r];
            a[r] = t;
        }
    }

};


} // end of namespace blogs


#endif

